
namespace Random
{

	class MultiplyWithCarryAdd
	{
	private:
		int mW, mZ;
	
	public:
		MultiplyWithCarryAdd(int s1, int s2) : mW(s1), mZ(s2)
		{
			//check seed is ok - 0 not permitted
			assert(s1, "seed must not be 0");
			assert(s2, "seed must not be 0");
		}

		//randim uint
		unsigned int randu32()
		{
			mZ = 36969 * (mZ & 65535) + (mZ >> 16);
			mW = 18000 * (mW & 65535) + (mW >> 16);
			return (mZ << 16) + mW;
		}

		//random signed int
		int rand32()
		{
			//reinterpret cast the bits, 32 random bits is 32 random bits
			//and any combination is ok for int
			unsigned int r = randu32();
			return *reinterpret_cast<int*>(&r);
		}

		//random float in [0,1] range
		float randfn()
		{
			//split the uint range over [0,1]. 
			double r = randu32()*(1.0/4294967295.0);
			return float(r);
		}

		float randf()
		{
			//split the uint range over [-1,1]. 
			double r = randu32()*(1.0/4294967295.0);
			return float((r-0.5f)*2.0f);
		}
	};

	//typedef a defacto generator. using MCA for now, (alledgedly) faster than MT.
	typedef MultiplyWithCarryAdd PRNG;


	class PerlinNoise
	{

		int mPermuteTable[512];

		static float fade(float t)
		{
			//6t^5 - 15t^4 + 10t^3
			return t*t*t*(t*(t*6 - 15) + 10);
		}

		static float lerp(float t, float a, float b)
		{
			return a + t*(b-a);
		}

		//silly optimised way to deal with calculating gradient since
		//the gradient vectors are all composed of unit elements.
		static float grad(int hash, float x, float y, float z)
		{
			int h = hash & 15;
			float u = h < 8 ? x : y;
			float v = h < 4 ? y : h==12||h==14 ? x : z;
			return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
		}

		void InitPermuteTable(PRNG& rand);
		
	public:
		
		PerlinNoise(PRNG& rand)
		{
			InitPermuteTable(rand);
		}

		float Sample3D(float x, float y, float z);
		float Sample2D(float x, float y)
		{
			return Sample3D(x, y, 0.0f);
		}
	};
};